#  This file is part of codeogre
#  Copyright (C) 2009 Johan Jordaan (www.johanjordaan.co.za)
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
sys.path.append('..\..')
import unittest

from codeogre.fsm import *

class FSMAcceptTestCases(unittest.TestCase):

    def setUp(self):
      pass

    def test_empty_input_string(self):
      ''' Empty fsm '''
      fsm = FSM()

      self.assertEqual(False,fsm.accepts(''))
      self.assertEqual(False,fsm.accepts('aa'))
      
    def test_empty_input_string(self):
      ''' Empty String Input '''
      fsm = FSM()
      s = FSMState(fsm,accepting=True)
      t = FSMTransition(source=fsm.start_state,destination=s,transition_function=lambda input,input_index:input[input_index]=='a')
      
      self.assertEqual(False,fsm.accepts(''))
      self.assertRaises(TypeError,fsm.accepts,None)

    def test_empty_input_array(self):
      ''' Empty Array Input '''
      fsm = FSM()
      s = FSMState(fsm,accepting=True)
      t = FSMTransition(source=fsm.start_state,destination=s,transition_function=lambda input,input_index:input[input_index]==1)
      
      self.assertEqual(False,fsm.accepts([]))
      self.assertRaises(TypeError,fsm.accepts,None)
      
    def test_one_transition_string(self):
      ''' a '''
      fsm = FSM()
      s = FSMState(fsm,accepting=True)
      t = FSMTransition(source=fsm.start_state,destination=s,transition_function=lambda input,input_index:input[input_index]=='a')
      
      self.assertEqual(True,fsm.accepts('a'))
      self.assertEqual(['a'],fsm.accepted_inputs)
      
      self.assertEqual(False,fsm.accepts('b'))
      self.assertEqual([],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('aa'))
      self.assertEqual(['a'],fsm.accepted_inputs)

      self.assertEqual(False,fsm.accepts('xxxx'))
      
    def test_one_transition_int_array(self):
      ''' 1 '''
      fsm = FSM()
      s = FSMState(fsm,accepting=True)
      t = FSMTransition(source=fsm.start_state,destination=s,transition_function=lambda input,input_index:input[input_index]==1)
      
      self.assertEqual(True,fsm.accepts([1]))
      self.assertEqual([[1]],fsm.accepted_inputs)
      
      self.assertEqual(False,fsm.accepts([2]))
      self.assertEqual([],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1,2,3]))
      self.assertEqual([[1]],fsm.accepted_inputs)

      self.assertEqual(False,fsm.accepts([4,5,6]))
      
    def test_two_transitions_serial_one_accepting_string(self):
      ''' ab '''
      fsm = FSM()
      s1 = FSMState(fsm)
      s2 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]=='a')
      t12 = FSMTransition(source=s1,destination=s2,transition_function=lambda input,input_index:input[input_index]=='b')
      
      self.assertEqual(True,fsm.accepts('ab'))
      self.assertEqual(['ab'],fsm.accepted_inputs)
     
      self.assertEqual(False,fsm.accepts('a'))
      self.assertEqual(False,fsm.accepts('b'))
      self.assertEqual(False,fsm.accepts('aa'))
      self.assertEqual(False,fsm.accepts('x'))
      self.assertEqual(False,fsm.accepts('xxxxxxxxxx'))
      
      self.assertEqual(True,fsm.accepts('abxxxxxxxx'))
      self.assertEqual(['ab'],fsm.accepted_inputs)
     
    def test_two_transitions_serial_one_accepting_array(self):
      ''' 1 2 '''
      fsm = FSM()
      s1 = FSMState(fsm)
      s2 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]==1)
      t12 = FSMTransition(source=s1,destination=s2,transition_function=lambda input,input_index:input[input_index]==2)
      
      self.assertEqual(True,fsm.accepts([1,2]))
      self.assertEqual([[1,2]],fsm.accepted_inputs)
     
      self.assertEqual(False,fsm.accepts([1]))
      self.assertEqual(False,fsm.accepts([2]))
      self.assertEqual(False,fsm.accepts([1,1]))
      self.assertEqual(False,fsm.accepts([22]))
      self.assertEqual(False,fsm.accepts([9,9,9,9,9,9]))
      
      self.assertEqual(True,fsm.accepts([1,2,3,4,5,6,7,8]))
      self.assertEqual([[1,2]],fsm.accepted_inputs)

    def test_two_transitions_choice_two_accepting_string(self):
      ''' a | b '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      s2 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]=='a')
      ts2 = FSMTransition(source=fsm.start_state,destination=s2,transition_function=lambda input,input_index:input[input_index]=='b')
      
      self.assertEqual(True,fsm.accepts('a'))
      self.assertEqual(['a'],fsm.accepted_inputs)
      
      self.assertEqual(True,fsm.accepts('b'))
      self.assertEqual(['b'],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('aaa'))
      self.assertEqual(['a'],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('bb'))
      self.assertEqual(['b'],fsm.accepted_inputs)
      
      self.assertEqual(False,fsm.accepts('x'))

    def test_two_transitions_choice_two_accepting_array(self):
      ''' 1 | 2 '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      s2 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]==1)
      ts2 = FSMTransition(source=fsm.start_state,destination=s2,transition_function=lambda input,input_index:input[input_index]==2)
      
      self.assertEqual(True,fsm.accepts([1]))
      self.assertEqual([[1]],fsm.accepted_inputs)
      
      self.assertEqual(True,fsm.accepts([2]))
      self.assertEqual([[2]],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1,1,1]))
      self.assertEqual([[1]],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([2,2]))
      self.assertEqual([[2]],fsm.accepted_inputs)
      
      self.assertEqual(False,fsm.accepts([9]))

    def test_two_transitions_serial_choice_two_accepting_string(self):
      ''' a | aa '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      s2 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]=='a')
      ts2 = FSMTransition(source=s1,destination=s2,transition_function=lambda input,input_index:input[input_index]=='a')
      
      self.assertEqual(True,fsm.accepts('a'))
      self.assertEqual(['a'],fsm.accepted_inputs)
      
      self.assertEqual(True,fsm.accepts('aa'))
      self.assertEqual(['aa','a'],fsm.accepted_inputs)
  
      self.assertEqual(True,fsm.accepts('aaaaaa'))
      self.assertEqual(['aa','a'],fsm.accepted_inputs)
      
    def test_two_transitions_serial_choice_two_accepting_string(self):
      ''' 1 | 1 1 '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      s2 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]==1)
      ts2 = FSMTransition(source=s1,destination=s2,transition_function=lambda input,input_index:input[input_index]==1)
      
      self.assertEqual(True,fsm.accepts([1]))
      self.assertEqual([[1]],fsm.accepted_inputs)
      
      self.assertEqual(True,fsm.accepts([1,1]))
      self.assertEqual([[1,1],[1]],fsm.accepted_inputs)
  
      self.assertEqual(True,fsm.accepts([1,1,1,1,1]))
      self.assertEqual([[1,1],[1]],fsm.accepted_inputs)

    def test_a_plus(self):
      ''' a+ '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]=='a')
      tloop = FSMTransition(source=s1,destination=s1,transition_function=lambda input,input_index:input[input_index]=='a')
      
      self.assertEqual(True,fsm.accepts('a'))
      self.assertEqual(['a'],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('aa'))
      self.assertEqual(['aa','a' ],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('aaaa'))
      self.assertEqual(['aaaa','aaa','aa','a' ],fsm.accepted_inputs)

    def test_one_plus(self):
      ''' 1 + '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      ts1 = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]==1)
      tloop = FSMTransition(source=s1,destination=s1,transition_function=lambda input,input_index:input[input_index]==1)
      
      self.assertEqual(True,fsm.accepts([1]))
      self.assertEqual([[1]],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1,1]))
      self.assertEqual([[1,1],[1] ],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1,1,1]))
      self.assertEqual([[1,1,1],[1,1],[1] ],fsm.accepted_inputs)

    def test_a_start(self):
      ''' a* '''
      fsm = FSM()
      fsm.start_state.accepting = True
      tloop = FSMTransition(source=fsm.start_state,destination=fsm.start_state,transition_function=lambda input,input_index:input[input_index]=='a')
      
      self.assertEqual(True,fsm.accepts(''))
      self.assertEqual([''],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('a'))
      self.assertEqual(['a','' ],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('aaaabb'))
      self.assertEqual(['aaaa','aaa','aa','a','' ],fsm.accepted_inputs)

    def test_one_star(self):
      ''' 1 * '''
      fsm = FSM()
      fsm.start_state.accepting = True
      tloop = FSMTransition(source=fsm.start_state,destination=fsm.start_state,transition_function=lambda input,input_index:input[input_index]==1)
      
      self.assertEqual(True,fsm.accepts([]))
      self.assertEqual([[]],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1]))
      self.assertEqual([[1],[] ],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1,1,1,1,2,2]))
      self.assertEqual([[1,1,1,1],[1,1,1],[1,1],[1],[] ],fsm.accepted_inputs)

    def test_a_question(self):
      ''' a? '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      fsm.start_state.accepting = True
      tloop = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]=='a')
      
      self.assertEqual(True,fsm.accepts(''))
      self.assertEqual([''],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('a'))
      self.assertEqual(['a','' ],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts('aaaabb'))
      self.assertEqual(['a','' ],fsm.accepted_inputs)

    def test_one_question(self):
      ''' 1 ? '''
      fsm = FSM()
      s1 = FSMState(fsm,accepting=True)
      fsm.start_state.accepting = True
      tloop = FSMTransition(source=fsm.start_state,destination=s1,transition_function=lambda input,input_index:input[input_index]==1)
      
      self.assertEqual(True,fsm.accepts([]))
      self.assertEqual([[]],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1]))
      self.assertEqual([[1],[] ],fsm.accepted_inputs)

      self.assertEqual(True,fsm.accepts([1,1,1,1,2,2]))
      self.assertEqual([[1],[] ],fsm.accepted_inputs)
      
    def test_a_question_b(self):
      ''' a?b '''
      fsm = FSM()
      s_a = FSMState(fsm,accepting=False)
      s_b = FSMState(fsm,accepting=True)
      t_s_a = FSMTransition(source=fsm.start_state,destination=s_a,transition_function=lambda input,input_index:input[input_index]=='a')
      t_s_b = FSMTransition(source=fsm.start_state,destination=s_b,transition_function=lambda input,input_index:input[input_index]=='b')
      t_a_b = FSMTransition(source=s_a,destination=s_b,transition_function=lambda input,input_index:input[input_index]=='b')
      
      self.assertEqual(False,fsm.accepts('a'))
      self.assertEqual(False,fsm.accepts('aa'))

      self.assertEqual(True,fsm.accepts('b'))
      self.assertEqual(['b'],fsm.accepted_inputs)
      self.assertEqual(True,fsm.accepts('ab'))
      self.assertEqual(['ab'],fsm.accepted_inputs)
      self.assertEqual(True,fsm.accepts('abb'))
      self.assertEqual(['ab' ],fsm.accepted_inputs)
      
   

      
suite = unittest.makeSuite(FSMAcceptTestCases)
          
if __name__ == '__main__':
  unittest.main()
